#ifndef _LCD_H_
#define _LCD_H_
#ifdef __cplusplus
 extern "C" {
#endif 

#include "lcd_config.h"
#include "lcd_font_simsun12.h"
#include "lcd_font_simsun16.h"
#include "lcd_font_hei31.h"
#include "lcd_font_hei48.h"
#include "lcd_type.h"

////////////////////////// 基本的驱动 API

/**
 * 初始化LCD, 仅上电后调用一次，执行时间可能达到数百ms。
 * 初始化将会设置操作窗口为整个屏幕。
 * @param dis_on true：初始化后开显示，false:初始化后关显示。
*/
void Lcd_Init(bool dis_on);

void Lcd_DispOff();

void Lcd_DispOn();

// 反显，驱动级反相切换。视芯片支持情况可能无效。
void Lcd_SetInvertDisplay(bool state);

// 设置操作窗口
// 低效率API，尽量少使用。数据发送完毕后才会返回。
void Lcd_SetWindow(u16 start_x, u16 start_y, u16 end_x, u16 end_y);

// 直接画一个点。低效率API，不建议使用。你应该使用操作缓存的替代API，然后 Lcd_FillData 一次性写入缓存。
// 注意：会改变当前操作窗口设置。将会等待数据传输结束。
// 返回：true:操作成功，false:总线忙。
bool Lcd_SetPoint(u16 x, u16 y, lcd_color_t point);

// [异步]在当前设置的窗口内填充数据（图片）
// 返回：true:操作成功，false:总线忙
// 可以通过总线数据发送完毕事件来判断是否操作结束，本驱动不提供事件通知。如果你的 _Lcd_PortWrite 是同步API，本函数也是同步函数。
bool Lcd_FillData(u8 *dat, u32 length);

/**
 * 在当前设置的窗口内填充纯色。低效率API，不建议使用。你应该使用操作缓存的替代API，然后 Lcd_FillData 一次性写入缓存。
 * 注意：为了加快刷屏速度，会占用128字节额外栈空间作为局部缓存
 * @param points 当前窗口的像素点数
 */
void Lcd_FillColor(lcd_color_t color, u32 points);

/**
 * 从32BIT颜色(ARGB)获取LCD支持的颜色格式（颜色格式转换）,A通道无效。
 * @param   c   ARGB格式颜色
 */
STATIC_FORCE_IN_LINE lcd_color_t Lcd_GetColorHex(u32 c)
{
    lcd_color_t r;
#if LCD_COLOR_BITS == 16
    #if LCD_COLOR_16_SWAP == 0
    /* Convert a 4 bytes per pixel in format ARGB32 to R5G6B5 format
        naive way (by calling lv_color_make with components):
                    r = ((c & 0xFF0000) >> 19)
                    g = ((c & 0xFF00) >> 10)
                    b = ((c & 0xFF) >> 3)
                    rgb565 = (r << 11) | (g << 5) | b
        That's 3 mask, 5 bitshift and 2 or operations

        A bit better:
                    r = ((c & 0xF80000) >> 8)
                    g = ((c & 0xFC00) >> 5)
                    b = ((c & 0xFF) >> 3)
                    rgb565 = r | g | b
        That's 3 mask, 3 bitshifts and 2 or operations */
    r.Full = (uint16_t)(((c & 0xF80000) >> 8) | ((c & 0xFC00) >> 5) | ((c & 0xFF) >> 3));
    #else
    /* We want: rrrr rrrr GGGg gggg bbbb bbbb => gggb bbbb rrrr rGGG */
    r.Full = (uint16_t)(((c & 0xF80000) >> 16) | ((c & 0xFC00) >> 13) | ((c & 0x1C00) << 3) | ((c & 0xF8) << 5));
    #endif
#elif LCD_COLOR_BITS == 32
    r.Full = c | 0xFF000000;
#else /*LCD_COLOR_BITS == 8*/
    /* We want: rrrr rrrr GGGg gggg bbbb bbbb => rrGGGbbb */
    r.Full = (uint8_t)(((c & 0xC00000) >> 16) | ((c & 0xE000) >> 10) | ((c & 0xFF) >> 5));
#endif
    return r;
}

//////////////////// 一些LCD操作API，如果没有使用专业GUI，这些API可能很有用 ////////////////
// 目前不支持缓存，使用上面的 Lcd_SetPoint 函数实现以下API，速度较慢，后续可以考虑加入缓存功能提升速度。

#ifdef LCD_USE_OPT_API
/**
 * 设置接下来操作的背景色
 * @param   c   新的背景色
 */
void Lcd_SetBgColor(lcd_color_t c);

/**
 * 设置接下来操作的背景色（32bit ARGB格式，A通道无效）。
 * @param   c   新的背景色（32bit ARGB格式，A通道无效）
 */
void Lcd_SetBgColorHex(u32 c);

/**
 * 设置接下来画笔颜色
 * @param   c   新的画笔颜色
 */
void Lcd_SetPaintColor(lcd_color_t c);

/**
 * 设置接下来画笔颜色（32bit ARGB格式，A通道无效）
 * @param   c   新的画笔颜色（32bit ARGB格式，A通道无效）
 */
void Lcd_SetPaintColorHex(u32 c);

/**
 * 设置字体的显示模式
*/
void Lcd_SetFontMode(lcd_font_mode_t fm_mode);

/**
 * 在LCD上显示字符串
 * @param   x       x 坐标
 * @param   y       y 坐标
 * @param   s       要显示的字符串，支持ASCII、GBK、GB2312
 */
void Lcd_ShowString(u16 x, u16 y, const char *s);

/**
 * 设置接下来显示文字的字体。
 * @param   font    字体
 */
void Lcd_SetFont(const lcd_font_t * font);

void Lcd_Line(u16 x0, u16 y0, u16 x1, u16 y1);

void Lcd_Circle(u16 x, u16 y, u16 r, bool fill);

void Lcd_Rectangle(u16 x0, u16 y0, u16 x1, u16 y1);

/**
 * 用背景色填充区域
 */
void Lcd_Clear(u16 x0, u16 y0, u16 x1, u16 y1);

/**
 * 用画笔颜色（前景色）填充任意区域
 */
void Lcd_Fill(u16 x0, u16 y0, u16 x1, u16 y1);

#endif

#ifdef __cplusplus
}
#endif 
#endif
